package groovy;

import limites.LimiteProyecto;
import limites.LimiteSector;

import org.junit.Before;
import org.junit.Test;

import tadp.tp.domain.Edificio;
import tadp.tp.domain.HomePersonas;
import tadp.tp.domain.HorarioDeReuniones;
import tadp.tp.domain.OrganizadorDeReuniones;
import tadp.tp.domain.Persona;
import tadp.tp.domain.Proyecto;
import tadp.tp.domain.Reservable;
import tadp.tp.domain.Reunion;
import tadp.tp.domain.Sala;
import accionesPosteriores.AccionDeUsuario;
import accionesPosteriores.AvisarAManagers;
import accionesPosteriores.AvisarAlTransporte;
import accionesPosteriores.AvisarHayCatering;
import accionesPosteriores.ReservarTodoElDia;

import static org.junit.Assert.*;

import java.util.ArrayList;

import Observers.ObserverBuilder;
import accionesPosteriores.AccionPosterior;
import accionesPosteriores.AvisarAlCatering;
import limites.Limite;
import limites.LimiteRol;
import tadp.tp.domain.condiciones.QueryBuilder;
import groovyDomain.Spec;
import tadp.tp.domain.Fecha;

class TestDSL {
	
	Edificio fg;
	Edificio f2;
	
	Proyecto proyectoV;
	Proyecto x;
	
	Persona persona6;
	Persona persona1;
	Persona persona2;
	Persona persona3;
	Persona persona4;
	Persona persona5;
	Persona persona7;
	Persona persona8;
	Persona persona9;
	Persona persona10;
	
	HorarioDeReuniones horario1;

	Reunion reunion1;
	OrganizadorDeReuniones organizador;
	HomePersonas centroDePersonas;
	Sala sala1;
	Sala sala2;
	ArrayList<Reservable> cosasAReservar;
	ArrayList<Reservable> cosasAReservar2;

	Limite limiteDe3Programadores;
	Limite limiteDe2Programadores;
	Limite limiteDe2Gerentes;
	Limite limiteDe3Gerentes;
	Limite limiteDe2DelProyectoX;
	Limite limiteDe2DelSector7g;
	
	ArrayList<AccionPosterior> accionesPosteriores = new ArrayList<AccionPosterior>();
	ArrayList<AccionPosterior> accionesPosterioresTest = new ArrayList<AccionPosterior>();
	AccionDeUsuario accionDeUsuarioAvisarHayCatering;
	AccionDeUsuario accionDeUsuarioReservarDia;
	
	@Before
	public void setUp() {
		
		fg = new Edificio();
		f2 = new Edificio();
		
		x = new Proyecto();
		proyectoV = new Proyecto();

		sala1 = new Sala(fg);
		sala2 = new Sala(fg);
		centroDePersonas = new HomePersonas();
		
		organizador = new OrganizadorDeReuniones(centroDePersonas, fg, x);
		
		fg.setSala(sala1);
		fg.setSala(sala2);
		
		accionesPosterioresTest.add(new AvisarAlCatering());
		accionesPosterioresTest.add(new AvisarAlTransporte());
		accionesPosterioresTest.add(new AvisarAManagers());
		
		accionDeUsuarioAvisarHayCatering = new AvisarHayCatering();
		accionDeUsuarioReservarDia = new ReservarTodoElDia();
		
		// crearPersona la agrega automaticamente al centroDePersonas
		persona1 = centroDePersonas.crearPersona("Diego", fg, x, "sector7G", "proyect lider", "07.00", "20.00", 25.00, 2.00, accionDeUsuarioReservarDia);
		
		persona2 = centroDePersonas.crearPersona("Martin", fg, x, "sector7G", "arquitecto", "07.00", "20.00", 19.00, 3.50, accionDeUsuarioReservarDia);
		
		persona3 = centroDePersonas.crearPersona("Braian", fg, x, "sector7G", "gerente", "07.00", "20.00", 25.00, 1.10, accionDeUsuarioAvisarHayCatering);
		
		persona4 = centroDePersonas.crearPersona("Sergio", fg, x, "sector7G", "gerente", "07.00", "18.00", 15.00, 2.00, accionDeUsuarioAvisarHayCatering);
		
		persona5 = centroDePersonas.crearPersona("Adriel", f2, proyectoV, "sector8i", "gerente", "06.00", "17.30", 20.00, 1.00, accionDeUsuarioReservarDia);
		
		persona6 = centroDePersonas.crearPersona("Areceli", f2, proyectoV, "sector7G", "programador", "07.00", "18.00", 22.00, 1.10, accionDeUsuarioReservarDia);
		
		persona7 = centroDePersonas.crearPersona("Teresa", f2, proyectoV, "sector2H", "programador", "06.00", "19.00", 10.00, 25.00, accionDeUsuarioAvisarHayCatering);
		
		persona8 = centroDePersonas.crearPersona("Nicolas", f2, proyectoV, "sector2H", "programador", "06.00", "17.00", 20.00, 12.00, accionDeUsuarioReservarDia);
		
		persona9 = centroDePersonas.crearPersona("Juan", f2, proyectoV, "sector2H", "programador", "06.00", "21.00", 20.00, 12.00, accionDeUsuarioReservarDia);
		
		persona10 = centroDePersonas.crearPersona("Juan", fg, proyectoV, "sector7G", "project manager", "06.00", "21.00", 20.00, 12.00, accionDeUsuarioAvisarHayCatering);
						
		limiteDe3Programadores = new LimiteRol("programador", 3);
		limiteDe2Programadores = new LimiteRol("programador", 2);
		limiteDe2Gerentes = new LimiteRol("gerente", 2);
		limiteDe3Gerentes = new LimiteRol("gerente",3);
		limiteDe2DelProyectoX = new LimiteProyecto(x, 2);
		limiteDe2DelSector7g = new LimiteSector("sector7G",2);
						
		organizador.setPersonas(centroDePersonas);
		
	}
	
	public void testPersonaCumpleCondiciones() {
		persona1.cumplis con estas condiciones
	}

	public void reservarSalaParaPersonasDeUnProyectoExitosamente() {
		def condiciones = new QueryBuilder().proyecto(x).buildCondicion()
		def sinLimite = null
		def observers = null
		
		organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un sinLimite programada entre las "11" y "12"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
		
		persona1.entre "11" y "12" del 10 del 10 noEstasDisponible
		persona2.entre "11" y "12" del 10 del 10 noEstasDisponible
		persona3.entre "11" y "12" del 10 del 10 noEstasDisponible
		persona4.entre "11" y "12" del 10 del 10 noEstasDisponible
		sala1.entre "11" y "12" del 10 del 10 noEstasDisponible		
	}
	
	public void costoReunionParaPersonasDeUnMismoProyecto() {
		def condicions = new QueryBuilder().proyecto(x).buildCondicion()
		def sinLimite = null
		def observers = null
		
		def reunion = organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un sinLimite programada entre las "16" y "17"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
		
		reunion.tu costo es 84.00
	}
	
	public void costoReunionParaPersonasDeDistintoProyecto() {
		def condicions = null
		def sinLimite = null
		def observers = null
		
		def reunion = organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un sinLimite programada entre las "07" y "08"
		para el dia 10 del 10 ademas ejecutar estas accionesPosterioresTest
		considerando tambien estos observers
		
		reunion.tu costo es 247.1
	}
	
	public void reunionConArquitecto() {
		def condicions = new QueryBuilder().rol("arquitecto").buildCondicion()
		def sinLimite = null
		def observers = null
		
		def reunion = organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un sinLimite programada entre las "09" y "10"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
		
		persona2.entre "09" y "10" del 10 del 10 noEstasDisponible
	}
	
	@Test(expected = RuntimeException.class)
	public void reservarSalaPara3GerentesPeroFallaPorqueEstanOcupados() {
		def condicions = new QueryBuilder().rol("gerente").buildCondicion()
		def observers = null
		
		organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un limiteDe3Gerentes programada entre las "13" y "14"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
	}
	
	@Test
	public void reservarSalaPara2GerentesConExito() {
		def condicions = new QueryBuilder().rol("gerente").buildCondicion()
		def observers = null
		
		organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un limiteDe2Gerentes programada entre las "16" y "17"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
		
		sala1.entre "16" y "17" noEstasDisponible
		persona2.entre "16" y "17" del 10 del 10 estasDisponible
		persona2.entre "16" y "17" del 10 del 10 noEstasDisponible
		persona2.entre "16" y "17" del 10 del 10 noEstasDisponible
	}
	
	@Test
	public void reservarSalaPara2PersonasDelProyectoXConExito() {
		def condiciones = new QueryBuilder().proyecto(x).buildCondicion()
		def observers = null

		organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un limiteDe2DelProyectoX programada entre las "16" y "17"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
		
		sala1.entre "16" y "17" del 10 del 10 noEstasDisponible
		persona1.entre "16" y "17" del 10 del 10 estasDisponible
		persona2.entre "16" y "17" del 10 del 10 noEstasDisponible
		persona3.entre "16" y "17" del 10 del 10 estasDisponible
		persona4.entre "16" y "17" del 10 del 10 noEstasDisponible
	}
	
	@Test
	public void reservarSalaPara3Programadoresy1ProyecLider() {
		def condiciones = new QueryBuilder().rol("programador").buildCondicion()
		def observers = null
		
		def reunion = organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un limiteDe3Programadores programada entre las "15" y "17"
		para el dia 10 del 10 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
		
		organizador.necesitoProyectLiderPara reunion;
		sala1.entre "15" y "17" del 10 del 10 noEstasDisponible
		persona6.entre "15" y "17" del 10 del 10 estasDisponible
		persona7.entre "15" y "17" del 10 del 10 noEstasDisponible
		persona8.entre "15" y "17" del 10 del 10 noEstasDisponible
		persona9.entre "15" y "17" del 10 del 10 noEstasDisponible
		persona1.entre "15" y "17" del 10 del 10 noEstasDisponible
		reunion requiereCatering
	}
	
	@Test
	public void reservarReunionQueUnProgramadorSeDaDeBajaYSeLoModificaPorUnGerente() {
		def condiciones = null
		def observers = new ObserverBuilder().observadorCriterioAsociadoDeSeleccion("gerente",organizador).build()
		
		def reunion = organizador.crea reunion con personas que cumplan estas condiciones
		limitandola	con un limiteDe3Programadores programada entre las "09" y "12"
		para el dia 15 del 11 ademas ejecutar estas accionesPosteriores
		considerando tambien estos observers
				
		persona8.darDeBajaDe reunion
		persona3.entre "09" y "12" del 15 del 11 noEstasDisponible
	}
	
}
